package cc.shacocloud.mirage.utils.annotation;

import cc.shacocloud.mirage.utils.reflection.ReflectUtil;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;

/**
 * {@link Annotation} 的 {@link Method} 的包装器
 *
 * @author 思追(shaco)
 * @see AttributeMethods
 */
public class AttributeMethod {
    
    @Getter
    @NotNull
    private final AttributeMethods attributeMethods;
    
    @NotNull
    private final Method method;
    
    public AttributeMethod(@NotNull AttributeMethods attributeMethods,
                           @NotNull Method method) {
        this.attributeMethods = attributeMethods;
        this.method = method;
    }
    
    /**
     * 获取该方法的返回值
     */
    public Object getValue(Object obj) {
        return ReflectUtil.invokeMethod(getSourceMethod(), obj);
    }
    
    /**
     * @return 获取源方法
     */
    public Method getSourceMethod() {
        return method;
    }
    
    /**
     * @return 获取源注解类型
     */
    public Class<? extends Annotation> getSourceAnnotationType() {
        return attributeMethods.getAnnotationType();
    }
    
    /**
     * 使该方法可以被访问
     */
    public void makeAccessible() {
        ReflectUtil.makeAccessible(method);
    }
    
    public Class<?> getDeclaringClass() {
        return method.getDeclaringClass();
    }
    
    public String getName() {
        return method.getName();
    }
    
    public int getModifiers() {
        return method.getModifiers();
    }
    
    public TypeVariable<Method>[] getTypeParameters() {
        return method.getTypeParameters();
    }
    
    public Class<?> getReturnType() {
        return method.getReturnType();
    }
    
    public Type getGenericReturnType() {
        return method.getGenericReturnType();
    }
    
    public Class<?>[] getParameterTypes() {
        return method.getParameterTypes();
    }
    
    public int getParameterCount() {
        return method.getParameterCount();
    }
    
    public Type[] getGenericParameterTypes() {
        return method.getGenericParameterTypes();
    }
    
    public Class<?>[] getExceptionTypes() {
        return method.getExceptionTypes();
    }
    
    public Type[] getGenericExceptionTypes() {
        return method.getGenericExceptionTypes();
    }
    
    public String toGenericString() {
        return method.toGenericString();
    }
    
    public boolean isBridge() {
        return method.isBridge();
    }
    
    public boolean isVarArgs() {
        return method.isVarArgs();
    }
    
    public boolean isSynthetic() {
        return method.isSynthetic();
    }
    
    public boolean isDefault() {
        return method.isDefault();
    }
    
    public Object getDefaultValue() {
        return method.getDefaultValue();
    }
    
    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
        return method.getAnnotation(annotationClass);
    }
    
    public Annotation[] getDeclaredAnnotations() {
        return method.getDeclaredAnnotations();
    }
    
    public Annotation[][] getParameterAnnotations() {
        return method.getParameterAnnotations();
    }
    
    public AnnotatedType getAnnotatedReturnType() {
        return method.getAnnotatedReturnType();
    }
    
    public Parameter[] getParameters() {
        return method.getParameters();
    }
    
    public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
        return method.getAnnotationsByType(annotationClass);
    }
    
    public AnnotatedType getAnnotatedReceiverType() {
        return method.getAnnotatedReceiverType();
    }
    
    public AnnotatedType[] getAnnotatedParameterTypes() {
        return method.getAnnotatedParameterTypes();
    }
    
    public AnnotatedType[] getAnnotatedExceptionTypes() {
        return method.getAnnotatedExceptionTypes();
    }
    
    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
        return method.isAnnotationPresent(annotationClass);
    }
    
    public Annotation[] getAnnotations() {
        return method.getAnnotations();
    }
    
    public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
        return method.getDeclaredAnnotation(annotationClass);
    }
    
    public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
        return method.getDeclaredAnnotationsByType(annotationClass);
    }
    
    
}
